import tkinter as tk
from tkinter import ttk, messagebox, simpledialog
import threading
from selenium import webdriver
from selenium.webdriver.edge.options import Options
from selenium.webdriver.edge.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.common.exceptions import TimeoutException, NoSuchElementException
import re
import os
from datetime import datetime

# ------------------ NEW: uiautomator2 импорт и настройки ------------------ #
import uiautomator2 as u2
import time
import logging
import sys

logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s - %(message)s',
    datefmt='%Y-%m-%d %H:%M:%S'
)

# ------------------ Глобальные переменные ------------------ #
successful_attempts = 0  # Общее число успешных попыток (накопительно)
failed_attempts = 0
batch_success_count = 0  # Счётчик успешных попыток в текущей "партии" (для лимита)
processing_thread = None  # Для отслеживания потока обработки
pause_event = threading.Event()
pause_event.set()  # Изначально не приостановлено
is_processing = False

# Пути к файлам
tokens_file = r"C:\Users\1\Desktop\VS 2022\Получение токенов ВК\tokens.txt"
failed_logins_file = r"C:\Users\1\Desktop\VS 2022\Получение токенов ВК\неуспешные логи.txt"
login_pass_file = r"C:\Users\1\Desktop\VS 2022\Получение токенов ВК\log pass.txt"
driver_path = r"C:\Users\1\Desktop\edgedriver_win64\msedgedriver.exe"
last_limit_file = r"last limit.txt"

# ------------------ Функции для работы с лимитом ------------------ #
def get_limit_value():
    """
    Возвращает лимит, введённый в поле, или 0, если значение некорректно.
    """
    try:
        return int(limit_entry.get())
    except ValueError:
        return 0

def save_last_limit():
    """
    Сохраняет текущее значение лимита в файл last limit.txt.
    """
    try:
        with open(last_limit_file, "w", encoding="utf-8") as f:
            f.write(limit_entry.get())
    except Exception as e:
        log_message(f"Ошибка при сохранении лимита: {e}", log_text, msg_type="error")

def load_last_limit():
    """
    Загружает сохранённое значение лимита из файла last limit.txt.
    Если файл не найден или возникла ошибка, возвращает "0".
    """
    try:
        with open(last_limit_file, "r", encoding="utf-8") as f:
            return f.read().strip()
    except Exception:
        return "0"

# ------------------ Функции для сценария uiautomator2 ------------------ #
def log_scenario_message(message):
    """
    Логирование в консоль для uiautomator2-сценария.
    """
    logging.info(message)

def lower_second_shade_and_toggle_switches():
    """
    Сценарий: опускаем шторку уведомлений, кликаем по первым двум свитчам,
    и поднимаем шторку обратно.
    """
    try:
        log_scenario_message("Подключение к устройству...")
        device = u2.connect()  # Для USB-подключения или укажите IP: u2.connect('192.168.x.x')
        log_scenario_message(f"Устройство подключено: {device.device_info}")

        device.open_quick_settings()
        time.sleep(1)
        log_scenario_message("Шторка опущена.")

        # Работа с первым свитчем
        switch1 = device.xpath('//*[@resource-id="com.android.systemui:id/quick_tile_layout"]/android.widget.Switch[1]')
        if switch1.wait(timeout=5):
            switch1.click()
            log_scenario_message("Первый свитч нажат.")
            time.sleep(1)
            switch1.click()
            log_scenario_message("Первый свитч повторно нажат.")
        else:
            log_scenario_message("Первый свитч не найден.")

        time.sleep(1)
        # Работа со вторым свитчем
        switch2 = device.xpath('//*[@resource-id="com.android.systemui:id/quick_tile_layout"]/android.widget.Switch[2]')
        if switch2.wait(timeout=5):
            switch2.click()
            log_scenario_message("Второй свитч нажат.")
        else:
            log_scenario_message("Второй свитч не найден.")

        log_scenario_message("Поднимаем шторку...")
        device.swipe(500, 1700, 500, 500, duration=0.5)
        time.sleep(1)
        log_scenario_message("Шторка поднята.")
    except Exception as e:
        log_scenario_message(f"Ошибка при выполнении сценария: {e}")

# ------------------ Функции GUI-логирования и обновления ------------------ #
def log_message(message, text_widget, msg_type="info"):
    """
    Логирование сообщений в текстовом виджете с временной меткой.
    msg_type может быть 'info', 'success' или 'error'.
    """
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    full_message = f"[{timestamp}] {message}\n"
    text_widget.config(state=tk.NORMAL)
    if msg_type == "info":
        text_widget.insert(tk.END, full_message, "info")
    elif msg_type == "success":
        text_widget.insert(tk.END, full_message, "success")
    elif msg_type == "error":
        text_widget.insert(tk.END, full_message, "error")
    text_widget.see(tk.END)
    text_widget.config(state=tk.DISABLED)

def append_token(token):
    """
    Добавляет токен в окно успешных токенов.
    """
    successful_tokens_text.config(state=tk.NORMAL)
    successful_tokens_text.insert(tk.END, token + "\n")
    successful_tokens_text.config(state=tk.DISABLED)

def append_failed_login(login, password):
    """
    Добавляет неуспешный логин и пароль в окно неуспешных попыток.
    """
    failed_logins_text.config(state=tk.NORMAL)
    failed_logins_text.insert(tk.END, f"{login}:{password}\n")
    failed_logins_text.config(state=tk.DISABLED)

def update_status_labels():
    total_accounts = len(read_login_passwords())
    remaining = total_accounts - (successful_attempts + failed_attempts)
    success_label.config(text=f"Успешные попытки: {successful_attempts}")
    failure_label.config(text=f"Неуспешные попытки: {failed_attempts}")
    count_label.config(text=f"Всего аккаунтов: {total_accounts}")
    remaining_label.config(text=f"Оставшиеся аккаунты: {remaining}")

# ------------------ Вспомогательные функции чтения/записи ------------------ #
def save_token_to_file(token, is_error=False):
    try:
        with open(tokens_file, "a", encoding='utf-8') as file:
            if is_error:
                file.write("ошибка\n")
            else:
                file.write(token + "\n")
        log_message(f"{'Ошибка' if is_error else 'Токен'} сохранён в файле: {tokens_file}", log_text, msg_type="info")
        if not is_error:
            append_token(token)
    except Exception as e:
        log_message(f"Ошибка при сохранении токена: {e}", log_text, msg_type="error")

def save_failed_login(login, password):
    try:
        with open(failed_logins_file, "a", encoding='utf-8') as file:
            file.write(f"{login}:{password}\n")
        log_message(f"Неуспешный логин сохранён в файле: {failed_logins_file}", log_text, msg_type="info")
        append_failed_login(login, password)
    except Exception as e:
        log_message(f"Ошибка при сохранении неуспешного логина: {e}", log_text, msg_type="error")

def read_login_passwords():
    if not os.path.exists(login_pass_file):
        log_message(f"Файл с логинами и паролями не найден: {login_pass_file}", log_text, msg_type="error")
        return []
    with open(login_pass_file, "r", encoding='utf-8') as file:
        accounts = [line.strip().split(":") for line in file if line.strip()]
    return accounts

# ------------------ Функция для запуска uiautomator2-сценария ------------------ #
def run_uiautomator_scenario():
    """
    Запускает uiautomator2-сценарий, затем ждёт 7 секунд.
    """
    try:
        log_message("Запуск uiautomator2-сценария...", log_text, msg_type="info")
        lower_second_shade_and_toggle_switches()
        log_message("Сценарий выполнен. Ожидание 7 секунд...", log_text, msg_type="info")
        time.sleep(7)
        log_message("Продолжение работы после сценария.", log_text, msg_type="info")
    except Exception as e:
        log_message(f"Ошибка при запуске uiautomator2-сценария: {e}", log_text, msg_type="error")

# ------------------ Основная логика работы с браузером ------------------ #
def open_browser(login, password):
    global successful_attempts, failed_attempts, batch_success_count

    log_message(f"Открытие браузера для аккаунта: {login}", log_text, msg_type="info")
    options = Options()
    options.add_argument("--inprivate")
    
    if hide_browser_var.get():
        options.add_argument("--headless")
        options.add_argument("--disable-gpu")
        log_message("Браузер запускается в скрытом режиме (headless).", log_text, msg_type="info")

    service = Service(driver_path)
    driver = webdriver.Edge(service=service, options=options)

    driver.get("https://vkhost.github.io/")
    log_message("Страница https://vkhost.github.io/ открыта.", log_text, msg_type="info")

    try:
        button = WebDriverWait(driver, 15).until(
            EC.element_to_be_clickable((By.CSS_SELECTOR, "button.btn[onclick='auth(6121396)']"))
        )
        button.click()
        log_message("Кнопка авторизации нажата.", log_text, msg_type="info")

        WebDriverWait(driver, 15).until(lambda d: len(d.window_handles) > 1)
        driver.switch_to.window(driver.window_handles[-1])
        log_message(f"Переключено на новую вкладку с URL: {driver.current_url}", log_text, msg_type="info")

        WebDriverWait(driver, 15).until(
            lambda d: d.current_url.startswith("https://oauth.vk.com/authorize?")
        )
        log_message(f"Страница авторизации ВКонтакте открыта: {driver.current_url}", log_text, msg_type="info")

        email_field = WebDriverWait(driver, 15).until(
            EC.presence_of_element_located((By.CSS_SELECTOR, "input[type='text'][name='email']"))
        )
        password_field = WebDriverWait(driver, 15).until(
            EC.presence_of_element_located((By.CSS_SELECTOR, "input[type='password'][name='pass']"))
        )

        email_field.send_keys(login)
        log_message("Логин введён.", log_text, msg_type="info")

        password_field.send_keys(password)
        log_message("Пароль введён.", log_text, msg_type="info")

        submit_button = WebDriverWait(driver, 15).until(
            EC.element_to_be_clickable((By.CSS_SELECTOR, "button.flat_button.oauth_button.button_wide[type='submit']"))
        )
        submit_button.click()
        log_message("Кнопка 'Войти' нажата.", log_text, msg_type="info")

        allow_button = WebDriverWait(driver, 15).until(
            EC.element_to_be_clickable((By.CSS_SELECTOR, "button.flat_button[onclick='return allow(this);']"))
        )
        allow_button.click()
        log_message("Кнопка подтверждения нажата.", log_text, msg_type="info")

        WebDriverWait(driver, 15).until(
            lambda d: d.current_url.startswith("https://oauth.vk.com/blank.html#access_token=")
        )
        log_message(f"Страница с токеном загружена: {driver.current_url}", log_text, msg_type="info")

        url = driver.current_url
        token_match = re.search(r"access_token=([^&]+)&expires_in", url)
        if token_match:
            token = token_match.group(1)
            save_token_to_file(token)
            successful_attempts += 1
            batch_success_count += 1
            log_message("Токен успешно получен.", log_text, msg_type="success")

            # Если указан ненулевой лимит и в партии набрано нужное количество,
            # автоматически приостанавливаем процесс и обнуляем счётчик партии.
            current_limit = get_limit_value()
            if current_limit > 0 and batch_success_count >= current_limit:
                log_message("Лимит токенов достигнут. Процесс приостановлен. Нажмите 'Восстановить' для продолжения.",
                            log_text, msg_type="info")
                pause_processing()
                batch_success_count = 0

        else:
            failed_attempts += 1
            save_token_to_file("", is_error=True)
            save_failed_login(login, password)
            log_message("Ошибка: Токен не найден в URL.", log_text, msg_type="error")
            append_token("ошибка")

    except TimeoutException:
        failed_attempts += 1
        save_token_to_file("", is_error=True)
        save_failed_login(login, password)
        log_message(f"Ошибка: Превышено время ожидания элемента на странице. Текущий URL: {driver.current_url}",
                    log_text, msg_type="error")
        append_token("ошибка")
    except NoSuchElementException:
        failed_attempts += 1
        save_token_to_file("", is_error=True)
        save_failed_login(login, password)
        log_message("Ошибка: Элемент не найден на странице.", log_text, msg_type="error")
        append_token("ошибка")
    except Exception as e:
        failed_attempts += 1
        save_token_to_file("", is_error=True)
        save_failed_login(login, password)
        log_message(f"Неожиданная ошибка: {e}", log_text, msg_type="error")
        append_token("ошибка")
    finally:
        driver.quit()
        log_message("Браузер закрыт.", log_text, msg_type="info")
        update_status_labels()

def process_all_accounts():
    global is_processing
    accounts = read_login_passwords()
    for login, password in accounts:
        pause_event.wait()  # Ожидаем, пока не будет возобновлено
        if not is_processing:
            break  # Если процесс был остановлен извне
        log_message(f"Обработка аккаунта: {login}", log_text, msg_type="info")
        open_browser(login, password)
    is_processing = False
    start_button.config(state=tk.NORMAL)
    pause_button.config(state=tk.DISABLED)
    resume_button.config(state=tk.DISABLED)
    restart_button.config(state=tk.DISABLED)
    log_message("Обработка всех аккаунтов завершена.", log_text, msg_type="info")

# ------------------ Функции управления потоком (старт/пауза/возобновить/перезапустить) ------------------ #
def start_browser_thread():
    global is_processing, processing_thread
    if is_processing:
        messagebox.showinfo("Информация", "Процесс уже запущен.")
        return
    # Сохраняем текущее значение лимита
    save_last_limit()
    is_processing = True
    pause_event.set()
    processing_thread = threading.Thread(target=process_all_accounts, daemon=True)
    processing_thread.start()
    start_button.config(state=tk.DISABLED)
    pause_button.config(state=tk.NORMAL)
    resume_button.config(state=tk.DISABLED)
    restart_button.config(state=tk.DISABLED)

def pause_processing():
    global pause_button, resume_button, is_processing
    if not is_processing:
        return
    pause_event.clear()
    log_message("Процесс приостановлен.", log_text, msg_type="info")
    pause_button.config(state=tk.DISABLED)
    resume_button.config(state=tk.NORMAL)
    restart_button.config(state=tk.NORMAL)

def resume_processing():
    global pause_button, resume_button, is_processing
    if not is_processing:
        return
    # Сохраняем лимит при восстановлении
    save_last_limit()
    pause_event.set()
    log_message("Процесс восстановлен.", log_text, msg_type="info")
    pause_button.config(state=tk.NORMAL)
    resume_button.config(state=tk.DISABLED)
    restart_button.config(state=tk.DISABLED)

def restart_processing():
    global is_processing, processing_thread, successful_attempts, failed_attempts, batch_success_count
    try:
        if processing_thread and processing_thread.is_alive():
            is_processing = False
            pause_event.set()
            processing_thread.join()
        successful_attempts = 0
        failed_attempts = 0
        batch_success_count = 0
        update_status_labels()
        log_message("Счётчики успешно сброшены.", log_text, msg_type="info")
        is_processing = True
        pause_event.set()
        processing_thread = threading.Thread(target=process_all_accounts, daemon=True)
        processing_thread.start()
        start_button.config(state=tk.DISABLED)
        pause_button.config(state=tk.NORMAL)
        resume_button.config(state=tk.DISABLED)
        restart_button.config(state=tk.DISABLED)
        log_message("Процесс перезапущен с первого аккаунта.", log_text, msg_type="info")
    except Exception as e:
        messagebox.showerror("Ошибка", f"Не удалось перезапустить процесс: {e}")
        log_message(f"Ошибка при перезапуске процесса: {e}", log_text, msg_type="error")

# ------------------ Функции копирования текста ------------------ #
def copy_successful_tokens():
    content = successful_tokens_text.get("1.0", tk.END).strip()
    if not content:
        messagebox.showinfo("Информация", "Нет токенов для копирования.")
        return
    root.clipboard_clear()
    root.clipboard_append(content)
    log_message("Токены скопированы в буфер обмена.", log_text, msg_type="info")

def copy_failed_logins():
    content = failed_logins_text.get("1.0", tk.END).strip()
    if not content:
        messagebox.showinfo("Информация", "Нет неуспешных логинов для копирования.")
        return
    root.clipboard_clear()
    root.clipboard_append(content)
    log_message("Неуспешные логины и пароли скопированы в буфер обмена.", log_text, msg_type="info")

def copy_selection():
    try:
        selected_text = root.focus_get().get(tk.SEL_FIRST, tk.SEL_LAST)
        root.clipboard_clear()
        root.clipboard_append(selected_text)
    except tk.TclError:
        pass

def select_all(text_widget):
    text_widget.tag_add(tk.SEL, "1.0", tk.END)
    text_widget.mark_set(tk.INSERT, "1.0")
    text_widget.see(tk.INSERT)

def show_context_menu(event):
    widget = event.widget
    if isinstance(widget, tk.Text):
        context_menu.post(event.x_root, event.y_root)

# ------------------ Окна для просмотра/очистки токенов и логинов ------------------ #
def open_tokens_window():
    if hasattr(open_tokens_window, 'window') and open_tokens_window.window.winfo_exists():
        open_tokens_window.window.focus()
        return

    tokens_window = tk.Toplevel(root)
    tokens_window.title("Успешные токены")
    tokens_window.geometry("600x400")

    frame = ttk.Frame(tokens_window, padding="10")
    frame.pack(fill=tk.BOTH, expand=True)

    tokens_text = tk.Text(frame, height=20, width=70, state=tk.DISABLED, wrap=tk.WORD)
    tokens_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

    scrollbar = ttk.Scrollbar(frame, orient=tk.VERTICAL, command=tokens_text.yview)
    scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
    tokens_text.config(yscrollcommand=scrollbar.set)

    def load_tokens():
        tokens_text.config(state=tk.NORMAL)
        tokens_text.delete("1.0", tk.END)
        if os.path.exists(tokens_file):
            with open(tokens_file, "r", encoding='utf-8') as file:
                tokens = file.read()
                tokens_text.insert(tk.END, tokens)
        else:
            tokens_text.insert(tk.END, "Файл с токенами не найден.")
        tokens_text.config(state=tk.DISABLED)

    def clear_tokens():
        if messagebox.askyesno("Подтверждение", "Вы уверены, что хотите очистить все токены?"):
            try:
                open(tokens_file, "w", encoding='utf-8').close()
                tokens_text.config(state=tk.NORMAL)
                tokens_text.delete("1.0", tk.END)
                tokens_text.config(state=tk.DISABLED)
                log_message("Все токены очищены.", log_text, msg_type="info")
                successful_tokens_text.config(state=tk.NORMAL)
                successful_tokens_text.delete("1.0", tk.END)
                successful_tokens_text.config(state=tk.DISABLED)
                update_status_labels()
            except Exception as e:
                messagebox.showerror("Ошибка", f"Не удалось очистить токены: {e}")

    load_tokens()

    button_frame = ttk.Frame(tokens_window)
    button_frame.pack(pady=5)

    clear_button = ttk.Button(button_frame, text="Очистить", command=clear_tokens)
    clear_button.pack()

    open_tokens_window.window = tokens_window

def open_failed_logins_window():
    if hasattr(open_failed_logins_window, 'window') and open_failed_logins_window.window.winfo_exists():
        open_failed_logins_window.window.focus()
        return

    failed_window = tk.Toplevel(root)
    failed_window.title("Неуспешные логины и пароли")
    failed_window.geometry("600x400")

    frame = ttk.Frame(failed_window, padding="10")
    frame.pack(fill=tk.BOTH, expand=True)

    failed_text = tk.Text(frame, height=20, width=70, state=tk.DISABLED, wrap=tk.WORD)
    failed_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

    scrollbar = ttk.Scrollbar(frame, orient=tk.VERTICAL, command=failed_text.yview)
    scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
    failed_text.config(yscrollcommand=scrollbar.set)

    def load_failed_logins():
        failed_text.config(state=tk.NORMAL)
        failed_text.delete("1.0", tk.END)
        if os.path.exists(failed_logins_file):
            with open(failed_logins_file, "r", encoding='utf-8') as file:
                failed_logins = file.read()
                failed_text.insert(tk.END, failed_logins)
        else:
            failed_text.insert(tk.END, "Файл с неуспешными логинами не найден.")
        failed_text.config(state=tk.DISABLED)

    def clear_failed_logins():
        if messagebox.askyesno("Подтверждение", "Вы уверены, что хотите очистить все неуспешные логины и пароли?"):
            try:
                open(failed_logins_file, "w", encoding='utf-8').close()
                failed_text.config(state=tk.NORMAL)
                failed_text.delete("1.0", tk.END)
                failed_text.config(state=tk.DISABLED)
                log_message("Все неуспешные логины и пароли очищены.", log_text, msg_type="info")
                failed_logins_text.config(state=tk.NORMAL)
                failed_logins_text.delete("1.0", tk.END)
                failed_logins_text.config(state=tk.DISABLED)
                update_status_labels()
            except Exception as e:
                messagebox.showerror("Ошибка", f"Не удалось очистить неуспешные логины: {e}")

    load_failed_logins()

    button_frame = ttk.Frame(failed_window)
    button_frame.pack(pady=5)

    clear_button = ttk.Button(button_frame, text="Очистить", command=clear_failed_logins)
    clear_button.pack()

    open_failed_logins_window.window = failed_window

# ------------------ Очистка всего сразу ------------------ #
def clear_all_logs():
    if messagebox.askyesno("Подтверждение", "Вы уверены, что хотите очистить все журналы, токены и неуспешные логины?"):
        try:
            open(tokens_file, "w", encoding='utf-8').close()
            open(failed_logins_file, "w", encoding='utf-8').close()
            log_text.config(state=tk.NORMAL)
            log_text.delete("1.0", tk.END)
            log_text.config(state=tk.DISABLED)

            successful_tokens_text.config(state=tk.NORMAL)
            successful_tokens_text.delete("1.0", tk.END)
            successful_tokens_text.config(state=tk.DISABLED)

            failed_logins_text.config(state=tk.NORMAL)
            failed_logins_text.delete("1.0", tk.END)
            failed_logins_text.config(state=tk.DISABLED)

            global successful_attempts, failed_attempts
            successful_attempts = 0
            failed_attempts = 0
            update_status_labels()

            log_message("Все журналы и данные очищены.", log_text, msg_type="info")

            if hasattr(open_tokens_window, 'window') and open_tokens_window.window.winfo_exists():
                open_tokens_window.window.destroy()
            if hasattr(open_failed_logins_window, 'window') and open_failed_logins_window.window.winfo_exists():
                open_failed_logins_window.window.destroy()

        except Exception as e:
            messagebox.showerror("Ошибка", f"Не удалось очистить журналы: {e}")

# ------------------ Настройка интерфейса tkinter ------------------ #
root = tk.Tk()
root.title("Получение токенов ВК")
root.geometry("1100x700")
root.resizable(False, False)

# Основной фрейм
main_frame = ttk.Frame(root, padding="10")
main_frame.pack(fill=tk.BOTH, expand=True)

# Верхний фрейм для кнопок и флажка
control_frame = ttk.Frame(main_frame)
control_frame.pack(fill=tk.X, pady=5)

start_button = ttk.Button(control_frame, text="Запустить", command=start_browser_thread)
start_button.pack(side=tk.LEFT, padx=5)

pause_button = ttk.Button(control_frame, text="Приостановить", command=pause_processing, state=tk.DISABLED)
pause_button.pack(side=tk.LEFT, padx=5)

resume_button = ttk.Button(control_frame, text="Восстановить", command=resume_processing, state=tk.DISABLED)
resume_button.pack(side=tk.LEFT, padx=5)

hide_browser_var = tk.BooleanVar()
hide_browser_check = ttk.Checkbutton(control_frame, text="Скрыть браузер", variable=hide_browser_var)
hide_browser_check.pack(side=tk.LEFT, padx=20)

restart_button = ttk.Button(control_frame, text="Перезапустить", command=restart_processing, state=tk.DISABLED)
restart_button.pack(side=tk.LEFT, padx=5)

update_labels_button = ttk.Button(control_frame, text="Обновить метки", command=update_status_labels)
update_labels_button.pack(side=tk.LEFT, padx=5)

clear_logs_button = ttk.Button(control_frame, text="Очистить все журналы", command=clear_all_logs)
clear_logs_button.pack(side=tk.LEFT, padx=5)

# ------------------ NEW: Поле для лимита токенов ------------------ #
limit_label = ttk.Label(control_frame, text="Лимит токенов:")
limit_label.pack(side=tk.LEFT, padx=(20, 5))
limit_entry = ttk.Entry(control_frame, width=5)
limit_entry.pack(side=tk.LEFT)
# При потере фокуса значение лимита сохраняется в файл
limit_entry.bind("<FocusOut>", lambda e: save_last_limit())
# Загружаем последнее сохранённое значение лимита (если есть)
limit_entry.insert(0, load_last_limit())

# Средний фрейм для статуса
status_frame = ttk.Frame(main_frame)
status_frame.pack(fill=tk.X, pady=5)

success_label = ttk.Label(status_frame, text="Успешные попытки: 0", foreground="green", cursor="hand2")
success_label.pack(side=tk.LEFT, padx=10)
success_label.bind("<Button-1>", lambda e: copy_successful_tokens())

failure_label = ttk.Label(status_frame, text="Неуспешные попытки: 0", foreground="red", cursor="hand2")
failure_label.pack(side=tk.LEFT, padx=10)
failure_label.bind("<Button-1>", lambda e: copy_failed_logins())

count_label = ttk.Label(status_frame, text="Всего аккаунтов: 0", foreground="blue")
count_label.pack(side=tk.LEFT, padx=10)

remaining_label = ttk.Label(status_frame, text="Оставшиеся аккаунты: 0", foreground="orange")
remaining_label.pack(side=tk.LEFT, padx=10)

# Нижний фрейм для логов и токенов
logs_frame = ttk.Frame(main_frame)
logs_frame.pack(fill=tk.BOTH, expand=True, pady=10)

# Журнал действий
log_frame = ttk.LabelFrame(logs_frame, text="Журнал действий")
log_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5)

log_text = tk.Text(log_frame, height=20, width=40, state=tk.DISABLED, wrap=tk.WORD)
log_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

log_scrollbar = ttk.Scrollbar(log_frame, orient=tk.VERTICAL, command=log_text.yview)
log_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
log_text.config(yscrollcommand=log_scrollbar.set)

log_text.tag_config("info", foreground="black")
log_text.tag_config("success", foreground="green")
log_text.tag_config("error", foreground="red")

# Успешные токены
tokens_frame = ttk.LabelFrame(logs_frame, text="Успешные токены")
tokens_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=5)

successful_tokens_text = tk.Text(tokens_frame, height=20, width=40, state=tk.DISABLED, wrap=tk.WORD)
successful_tokens_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

tokens_scrollbar = ttk.Scrollbar(tokens_frame, orient=tk.VERTICAL, command=successful_tokens_text.yview)
tokens_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
successful_tokens_text.config(yscrollcommand=tokens_scrollbar.set)

successful_tokens_text.tag_config("success", foreground="green")
successful_tokens_text.tag_config("error", foreground="red")

# Неуспешные логины
failed_frame = ttk.LabelFrame(main_frame, text="Неуспешные логины и пароли")
failed_frame.pack(fill=tk.BOTH, expand=True, padx=5, pady=10)

failed_logins_text = tk.Text(failed_frame, height=10, width=80, state=tk.DISABLED, wrap=tk.WORD)
failed_logins_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

failed_scrollbar = ttk.Scrollbar(failed_frame, orient=tk.VERTICAL, command=failed_logins_text.yview)
failed_scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
failed_logins_text.config(yscrollcommand=failed_scrollbar.set)

failed_logins_text.tag_config("error", foreground="red")

# Инициализация логов
log_message("Журнал действий:", log_text, msg_type="info")

# Создание общего контекстного меню
context_menu = tk.Menu(root, tearoff=0)
context_menu.add_command(label="Копировать", command=copy_selection)
context_menu.add_command(label="Выбрать всё", command=lambda: select_all(root.focus_get()))

log_text.bind("<Button-3>", show_context_menu)
successful_tokens_text.bind("<Button-3>", show_context_menu)
failed_logins_text.bind("<Button-3>", show_context_menu)

update_status_labels()

root.mainloop()
